//R5
#include "dcb.h"
#include "R5.h"
#include <stdio.h>
#include <dos.h>

int mask;
void interrupt (*oldfunc) ();
dcb *newDCB;

/*
COM_OPEN

eflag_p: pointer to an integer event flag within the calling program
baud_rate: integer value representing the desired baud rate

RETURNS:
0 if no error
-101 if invalid even flag pointer
-102 if invalid baud rate divisor
-103 if port already open

FUNCTIONALITY:
Initialize the newDCB
Set the interrupt vector to the new handler address
Computer and store the baud rate divisor
Set other characteristics
Enable all of the necessary interrupts
*/

int com_open(int *eflag_p, int baud_rate)
{
	
	long brd;  //baud rate devisor

	if(eflag_p == NULL){return(ERR_SUP_INVEFP);}
	else if(baud_rate < 0){return(ERR_SUP_INVBRD);}
	else if(newDCB->flag != 0){return(ERR_SUP_PRTOPN);}
	else
	{
		newDCB->flag = 0;  //Set device flag to OPEN
		newDCB->event_flag = eflag_p;  //saves event flag
		newDCB->status = 0;  //Set device status to IDLE
		newDCB->ring_buffer_in = 0;
		newDCB->ring_buffer_out = 0;
		newDCB->ring_buffer_count = 0;
		oldfunc = getvect(COM1_INT_ID);
		setvect(COM1_INT_ID, &io_interupt());  //com_int is the name of the interupt handler
		brd = 115200 / (long) baud_rate;
		outportb(COM1_LC, 0x80);
		outportb(COM1_BRD_LSB, brd&0xFF);
		outportb(COM1_BRD_LSB,(brd >> 8)&0xFF);
		outportb(COM1_LC, 0x03);

		disable();                    //Enable com1 for PIC mask register
		mask = inportb(PIC_MASK);
		mask = mask & ~0x3F8;
		outportb(PIC_MASK, mask);
		enable();

		outportb(COM1_MC, 0x08); //enables serial interrupts
		outport(COM1_INT_EN, 0x01); //enables input ready interupts
		return 0;  //No error
	}
}

/*
COM_CLOSE

TAKES NO PARAMETERS

RETURNS:
0 if no error
-201 if serial port not open

FUNCTIONALITY:
Check that the port is already open (return error code if not)
Close the newDCB
Disable the appropriate level in the PIC mask register
Loading 0x00 into the Modem Status and Interrupt Enable registers
Restore the original interrupt vector
*/

int com_close(void)
{
	if(newDCB->flag != 1){return(ERR_SUP_PRTNOP);}
	else
	{
		newDCB->flag = 0;

		disable();                 //This enables, but needs to disable appropriate level
		mask = inportb(PIC_MASK);
		mask = mask & ~0x80;
		outportb(PIC_MASK, mask);
		enable();

		outportb(COM1_MS, 0x00);
		outportb(COM1_INT_EN, 0x00);

		setvect(COM1_INT_ID, &oldfunc);  //Needs to be original interupt vector
		return 0;
	}
}

/**
int com_read(char * buf_p, int *count_p);

Parameters
buf_p: far pointer to the starting address of the buffer to 
receive the input characters

count_p: address of an integer count value indicating the 
number of characters to be read

Returns
0 if no error
-301 if port not open
-302 if invalid buffer address
-303 if invalid count address or count value
-304 if device is busy
**/

/*In MPX all data transfers are 8-bit, so only inportb and outportb*/

int com_read(char* buf_p, int* count_p){

	//check if params are null
	if(buf_p && count_p){
		newDCB->in_buff* = &buf_p;
		newDCB->in_count* = &count_p; //total number of chars in request buffer
		newDCB->in_done = 0; //index for request buffer
		newDCB->event_flag = 0;	//clear event flag
		newDCB->status = DCB_STATUS_READING;

		disable();//disable interrupts
		
		//begin reading
		if(newDCB->ring_buffer_count > 0){
			do{
				newDCB->in_buff[newDCB->in_done] = newDCB->ring_buffer[rewDCB->ring_buffer_out];
				newDCB->ring_buffer_count--;
				rewDCB->ring_buffer_out++;
				newDCB->in_done++;
			}while((newDCB->ring_buffer_count > 0)
				&&(newDCB->in_done < newDCB->in_count)
				&&(newDCB->ring_buffer[rewDCB->ring_buffer_out] != '\r'));
			enable(); //re enable interrupts
			if(newDCB->in_done < newDCB->in_count){
				return 0;
			}else{
				newDCB->in_buff[strlen(newDCB->in_buff)] = '\0'; //null terminate input buffer
				newDCB->status = DCB_STATUS_IDLE;
				return newDCB->in_count; //return how many chars were read to requestor
			}
				
		}
	}
	else
	//error message
	
	return -1;
}


/**
int com_write(char * buf_p, int *count_p);

Parameters
buf_p: pointer to the starting address of the buffer containing 
the block of characters to be written

count_p: address of the integer count value indicating the 
number of characters to be written

Return
0 if no error
-401 if serial port not open
-402 is invalid buffer address
-403 if invalid count address or count value
-404 if device bus
**/

int com_write(char* buf_p, int* count_p){

	return 0;
}

/**
void interrupt io_interrupt()
Outline:
If port is not open, clear the interrupt by sending the end of interrupt 
code to the PIC command register and return.  You clear the 
interrupt to indicate that it has been handled
Otherwise, use inport b to read an int from the Interrupt ID Register to 
determine the cause of the interrupt.

The value in the interrupt ID register indicates what type of interrupt 
was generated, either a read or a write.  A description of what bits 
in this value contains the information we need is in the manual.  
However, one way to find the value is to perform a bit wise and 
operation (&) between the integer value from the interrupt ID 

register and 0x07:
– If 2, call the write second level interrupt handler
– If 4, call the read second level interrupt handler
Clear the interrupt by sending EOI to the PIC command Register
**/

void interrupt io_interrupt(){
	int intID;					//Wasn't sure if I could use mask, or if I
								//could use a local variable
	if (newDCB->flag == 0){
		PIC_CMD = EOI;
		return ERR_SUP_PRTNOP;
	}
	else {
		intID = inportb(COM1_INT_ID);
		
		if ((intID & 0x07) == 2){        	//Write interrupt, call second
			write_int_handler();		//level write interrupt handler
		}
		else if ((intID & 0x07) ==4){		//Read interrupt, call second
			read_int_handler();			//level read interrupt handler
		}
		else {
			return ERR_INVALID_INT_ID;
		}
	}
}

void write_int_handler(){
	char tmp;
	if (newDCB->status != DCB_STATUS_WRITING){
		return;
	}
	if (newDCB->out_count > 0){
		COM1_BASE = newDCB->out_buff;		//write char to output register (SO WRONG!)
	if (newDCB->ring_buffer_count == 0){  	//Buffer Exhausted, set to IDLE
		newDCB->status = DCB_STATUS_IDLE;
		newDCB->event_flag = IO_COMPLETE;
		mask = inportb(COM1_INT_EN);
		mask = mask & ~0x02;
		outportb(COM1_INT_EN ,mask);
	}
}

void read_int_handler(){
	
	char tmp;
	tmp = COM1_BASE;	//reading in character from input register (so wrong) 
	if (newDCB->status != DCB_STATUS_READING){
		if (newDCB->ring_buffer_count == RING_BUFFER_SIZE){
			tmp = '\0'//discard character?
			return;
		}
		else {
			newDCB->ring_buffer[newDCB->ring_buffer_in] = tmp; //WRONG ... so Wrong
		}
	}
	if (newDCB->status == DCB_STATUS_READING){
		newDCB->in_buff = tmp
		newDCB->in_count++;
		if (tmp == '\r' || newDCB->in_count == 80){	//WRONG HERE TOO!
			strcat(newDCB->in_buff, '\0');
			newDCB->status = DCB_STATUS_IDLE;
			newDCB->event_flag = IO_COMPLETE;
			newDCB->in_count = newDCB->in_done;
			return newDCB->in_count;
		}
	}
}